package com.feonix.common.basedao;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.util.Iterator;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.feonix.common.annotation.AnnotationBean;
import com.feonix.common.annotation.Column;
import com.feonix.common.annotation.GeneratorType;
import com.feonix.common.annotation.Id;
import com.feonix.common.annotation.Index;
import com.feonix.common.annotation.Indexes;
import com.feonix.common.annotation.OnlyQuery;
import com.feonix.common.annotation.Table;
import com.feonix.common.util.AnnotationUtil;
import com.feonix.common.util.SqlUtil;
import com.feonix.common.util.StringUtil;

public class EntityResolving {

	private static final Log logger = LogFactory.getLog(EntityResolving.class);

	public static void resolving(Class<?> clazz) {
		if (getEntityProperty(clazz)) {
			return;
		}
		Table table = AnnotationUtil.findAnnotationFromClass(clazz, Table.class);
		if (table == null) {
			return;
		}
		AnnotationUtil.findAnnotationFromClass(clazz, Index.class);
		List<AnnotationBean<Column>> columnList = AnnotationUtil.findAnnotationFromFields(clazz, Column.class);
		List<AnnotationBean<Id>> idList = AnnotationUtil.findAnnotationFromFields(clazz, Id.class);
		if (columnList == null) {
			logger.error("none of the columns in entity " + clazz.getCanonicalName());
			return;
		}
		if ((idList != null) && (idList.size() > 1)) {
			logger.error("lots of ids in entity " + clazz.getCanonicalName());
			return;
		}
		String str = table.name();
		boolean bool = table.create();
		Entity entity = new Entity();
		entity.setTableName(str);
		entity.setCreate(bool);

		EntityProperty entityProperty = null;
		for (Iterator<AnnotationBean<Column>> columnIterator = columnList.iterator(); columnIterator.hasNext();) {
			AnnotationBean<Column> tmpColumn = columnIterator.next();
			entityProperty = getEntityProperty(tmpColumn);
			entity.addEntityProperty(entityProperty);
			if (entityProperty.isPk()) {
				entity.setIdProperty(entityProperty);
			}
		}

		List<AnnotationBean<OnlyQuery>> onlyQueryList = AnnotationUtil.findAnnotationFromFields(clazz, OnlyQuery.class);
		AnnotationBean<OnlyQuery> onlyQueryAnnotation = null;
		if (onlyQueryList != null) {
			for (Iterator<AnnotationBean<OnlyQuery>> onlyQueyIterator = onlyQueryList.iterator(); onlyQueyIterator
					.hasNext();) {
				onlyQueryAnnotation = onlyQueyIterator.next();
				entityProperty = getEntityPropertyOnlyQuery(onlyQueryAnnotation);
				entity.addOnlyQueryEntityProperty(entityProperty);
			}
		}

		List<Field> fieldList = AnnotationUtil.findNoAnnotationFields(clazz);
		Iterator<Field> fieldIterator = null;
		if (fieldList != null) {
			for (fieldIterator = fieldList.iterator(); fieldIterator.hasNext();) {
				Field tempField = fieldIterator.next();
				entityProperty = getEntityProperty(tempField);
				entity.addGeneralEntityProperty(entityProperty);
			}
		}

		Indexes indexes = AnnotationUtil.findAnnotationFromClass(clazz, Indexes.class);
		if (indexes != null) {
			String indexName = null;
			String[] fieldNameArray = null;
			Index[] indexArray = indexes.value();
			for (Index index : indexArray) {
				indexName = index.indexName();
				fieldNameArray = index.fieldNames();
				if (StringUtil.isEmpty(indexName)) {
					indexName = "index_" + str + "_" + StringUtil.join(fieldNameArray, "_");
				}
				entity.addIndex(indexName, fieldNameArray);
			}
		}

		EntityManager.addEntity(clazz, entity);
	}

	private static boolean getEntityProperty(Class<?> clazz) {
		return (EntityManager.getEntity(clazz) != null);
	}

	private static EntityProperty getEntityProperty(AnnotationBean<Column> annotationBean) {
		EntityProperty entityProperty = null;
		if (annotationBean == null) {
			return entityProperty;
		}
		entityProperty = new EntityProperty();
		Column column = annotationBean.getAnnotation();
		Id id = annotationBean.getField().getAnnotation(Id.class);
		if (id != null) {
			entityProperty.setPk(true);
			entityProperty.setGeneratorType(id.generatorType());
			Class<? extends BaseIdGenerator<? extends Serializable>> object = id.generator();
			if (object != DefaultIdGenerator.class) {
				try {
					entityProperty.setGeneratorType(GeneratorType.CUSTOM);
					entityProperty.setGenerator(object.newInstance());
				} catch (Exception exception) {
					logger.error("resolvingColumn error", exception);
				}
			}
		}
		entityProperty.setFieldName(annotationBean.getName());
		entityProperty.setFieldType(annotationBean.getFieldType());
		if (StringUtil.isEmpty(column.name()))
			entityProperty.setColumnName(annotationBean.getField().getName().toLowerCase());
		else {
			entityProperty.setColumnName(column.name());
		}

		entityProperty.setColumnType(column.type());
		int[] columnLengthArray = SqlUtil.resolvingLength(column.type(), column.decimalLenght());
		if (column.length() == 0)
			entityProperty.setLength(columnLengthArray[0]);
		else {
			entityProperty.setLength(column.length());
		}
		entityProperty.setDecimalLenght(columnLengthArray[1]);
		entityProperty.setUpdate(column.update());
		entityProperty.setUnique(column.unique());
		entityProperty.setNotNull(column.notNull());
		return entityProperty;
	}

	private static EntityProperty getEntityPropertyOnlyQuery(AnnotationBean<OnlyQuery> annotationBean) {
		EntityProperty entityProperty = null;
		if (annotationBean == null) {
			return entityProperty;
		}
		entityProperty = new EntityProperty();
		OnlyQuery onlyQuery = annotationBean.getAnnotation();
		entityProperty.setFieldName(annotationBean.getName());
		entityProperty.setFieldType(annotationBean.getFieldType());
		if (StringUtil.isEmpty(onlyQuery.name()))
			entityProperty.setColumnName(annotationBean.getField().getName().toLowerCase());
		else {
			entityProperty.setColumnName(onlyQuery.name());
		}
		return entityProperty;
	}

	private static EntityProperty getEntityProperty(Field field) {
		EntityProperty entityProperty = null;
		if (field == null) {
			return entityProperty;
		}
		entityProperty = new EntityProperty();
		entityProperty.setFieldName(field.getName());
		entityProperty.setFieldType(field.getType());
		entityProperty.setColumnName(field.getName().toLowerCase());
		return entityProperty;
	}
}
